home *** CD-ROM | disk | FTP | other *** search
- COMMENT &
-
- XFIND Filter
- Command
- -------------------------------------------------------------------------
- Purpose: This filter sends to the standard output device all
- lines from the filenames specified in the command line
- that contain the specified string. Letter case is
- IGNORED in the comparisons, unless an exact match is
- requested by the /E switch. Command line parameters may
- be separated by one or more blanks, tabs, or commas.
-
- Format: XFIND [/C] [/E] [/N] [/V] "pat" [[d:][path]filename[.ext]...]
-
- Type: Internal External
- ***
-
- Remarks: The search is restricted to strings found in a single
- lines. Patterns split across line boundaries will not
- be recognized.
-
- The /C parameter causes XFIND to display only a count of
- the number of matching occurrences of string in each
- file, without displaying the matching lines from the
- file.
-
- The /E parameter requests an exact match with respect to
- letter case in the string.
-
- The /N parameter causes the relative line number of each
- matching line to be displayed ahead of the line from the
- file.
-
- The /V parameter causes all lines NOT containing the
- string to be displayed.
-
- The string must be enclosed in double quotes. Two
- quotes in succession are taken as a single quote.
-
- Unlike FIND, global filename characters ARE allowed in
- the filenames or extensions, but alas, due to DOS
- 2.0 limitations, not in directory paths.
-
- Examples:
- XFIND /C "equ" *.asm ! Count the number of equ's
- XFIND "foobar" *.for,*.asm,*.pas
- xfind /e "Tel:" phone1 phone2 ph*.txt phone3
-
- Error returns: 0 - success
- 1 - empty pattern
- 2 - command line incomplete
- 3 - one or more file open failures (some output may be
- produced)
- 4 - file not found in wildcard expansion
- 5 - file read error
-
- -------------------------------------------------------------------------
-
- The code has been developed from a disassembly of the IBM PC FIND Filter
- command.
-
- The 8088 has single instructions for scanning a string for an exact
- match or mismatch with a single character, but none for doing this with
- translation. Using translation turns one of these instructions into a
- 5-instruction loop with 5 entry/exit instructions, and the other becomes
- a 9-instruction loop with 4 entry/exit instructions. A test in a large
- file directory showed this routine to be about 15% slower than the FIND
- utility (87 sec vs 77 sec), which is not an unacceptable overhead.
-
- [03-Feb-84] Nelson H.F. Beebe, University of Utah
- [01-Mar-84] Brad Davis, Drafting Services Ltd, Salt Lake City, UT
- (changed code to allow use as .COM file and have big
- input buffer)
- &
-
- include ascii.inc
- include dos.inc
-
- MAXBUF equ 58*1024 ; Buffer size - freely variable within
- ; segment size limitation. Original value
- ; was 4096. Code takes 3K, leave 3K for stack
-
- assume cs:findc,ds:findc,es:findc,ss:findc
- findc segment para public 'code'
-
- org 100H ; where a .COM file begins
- start: jmp find ; jump around constant data
-
- db "MAUlloa/Microsoft/V126"
- colon db ':',' ' ; 16
- linstr db '[' ; 18
- intstr db 8 dup (0) ; 19
-
- ; Flags recording switch settings. These should be consecutive bytes.
- ; A value FLAGSET means the flag is set, any other means not set
-
- FLAGSET equ -1 ; value signalling flag set
-
- flags equ $ ; symbol used to index table
- notflg db 0 ; /V
- cntflg db 0 ; /C
- numflg db 0 ; /N
- exactflg db 0 ; /E
-
-
- ; return code flags in order of increasing severity. The highest
- ; met is returned
-
- RC_OKAY equ 0 ; success
- RC_PATT equ 1 ; empty pattern
- RC_PARM equ 2 ; bad command line syntax
- RC_FILE equ 3 ; file open failure
- RC_NFND equ 4 ; file not found
- RC_READ equ 5 ; file read error
-
- rc db RC_OKAY ; return code
-
- db 0,0 ; 24,25
- matches dw ; 26
- lineno dw ; 28
-
- find: ; Begin main program
- mov rc,RC_OKAY ; tentative return code
- mov ah,$DOS_GETVERSION
- int $DOS
- cmp al,2 ; version 2 or later?
- jge cont ; jump if yes
- mov dx,offset baddos
- mov ah,$DOS_STROUT ; print string
- int $DOS
- xor ax,ax ; clear ax
- mov ah,$DOS_EXIT
- int $DOS
-
- assume cs:findc,ds:findc
-
- cont: ; continue main program now that DOS
- mov si,81h ; Address in PSP of command line
- call skipsp ; Skip leading spaces
- or bx,bx ; Test skip result, non-zero at CR
- jz haveparam ; jump if have command line data
-
- cnterr:
- mov dx,offset numerr; error - need more parameters
- mov cl,numlen ; message and message length in dx,cl
- call writedserr ; write a message
- mov al,RC_PARM ; return code
- call setrc
- jmp errexit ; abort
-
- haveparam:
- mov ah,$DOS_SWITCH ; get switchar (undocument internal call)
- mov al,$DOS_SWITCH_GET
- int $DOS
- push dx ; save switch character
-
- scanswitch: ; begin loop to scan for switches
- lodsb ; get byte from [si] to al, increment si
- cmp al,' ' ; blank?
- je moresp ; jump if so to flush more space
- cmp al,.HT ; tab?
- je moresp ; jump if so to flush more space
- cmp al,.CR ; end-of-line?
- je cnterr ; jump if so -- error - need more data
- pop dx ; restore switch character
- cmp al,dl ; switch character?
- jne scanpat ; jump if not - now expect to find "pattern"
- push dx ; save switch character again
- lodsb ; get byte from [si] to al, increment si
- cmp al,' ' ; blank?
- je moresp ; jump if so to flush more space
- cmp al,.HT ; tab?
- je moresp ; jump if so to flush more space
- cmp al,.CR ; end-of-line?
- je cnterr ; jump if so -- error - need more data
- call lcuc ; convert to upper-case
- mov bx,offset notflg
-
- cmp al,'C' ; /C? (count matching lines only)
- je setcnt ; jump if yes
-
- cmp al,'E' ; /E? (exact match)
- je setexact ; jump if yes
-
- cmp al,'N' ; /N? (line numbers)
- je setnum ; jump if yes
-
- cmp al,'V' ; /V? (invert search)
- je setnot ; jump if yes
-
- mov pattrn[0],al ; unrecognized switch character
- mov dx,offset prmerr; message
- mov cl,prmlen ; and length
- call writedserr ; go write it
- mov dx,offset pattrn; NUL
- mov cx,1 ; 1 character
- call writedserr ; write the NUL
- mov dx,offset crlf ; and a CR LF
- mov cx,2
- call writedserr
- jmp scanswitch ; continue switch scan
-
- setcnt: ; /C found
- mov di,cntflg-flags ; offset in switch table
- jmp short setflg ; go set it
-
- setexact:
- mov di,exactflg-flags ; offset in switch table
- jmp short setflg ; go set it
-
- setnum: ; /N found
- mov di,numflg-flags ; offset in switch table
- jmp short setflg ; go set it
-
- setnot: ; /V found
- mov di,notflg-flags ; offset in switch table
- ; fall through to setflg
-
- setflg: ; set the switch
- mov byte ptr [bx+di],FLAGSET
- jmp scanswitch ; continue switch scan
-
- moresp: ; flush white space in command line
- dec si ; backup to space just found
- call skipsp ; go skip some space
- or bx,bx ; end-of-line reached?
- jz scanswitch ; jump if not
- jmp cnterr ; error - expected more data
-
- scanpat: ; Begin code to scan "pattern"
- cmp al,'"' ; Quote?
- jne nopat ; Jump if not - error if no pattern
- mov di,offset pattrn; where to store the pattern
- xor cx,cx ; clear count of pattern length
-
- patch:
- lodsb ; get byte from [si] to al, increment si
- cmp al,.CR ; end-of-line?
- jne stlpat ; jump if not, still in pattern
-
- nopat: ; here if pattern absent or incomplete
- mov dx,offset synerr; message
- mov cl,synlen ; and length
- call writedserr ; write it
- mov al,RC_PATT ; return code
- call setrc
- jmp errexit ; abort
-
- stlpat: ; here if still in pattern
- cmp al,'"' ; quote?
- jne stoch ; jump if not to save character
- lodsb ; get byte from [si] to al, increment si
- cmp al,'"' ; pair of quotes?
- je stoch ; yes, save only one of them
- dec si ; no, must be end of pattern
- mov patlen,cx ; save pattern length
- or cx,cx ; was it zero?
- jnz havpat ; jump if not, have valid pattern
- mov al,RC_PATT ; return code for empty pattern
- call setrc
- jmp errexit ; abort
-
- stoch: ; store pattern character
- stosb ; store byte in al at [di], increment di
- inc cx ; count the character
- jmp patch ; go back for more
-
- havpat:
- call skipsp ; flush more white space
- or bx,bx ; end-of-line yet?
- jz havfil ; no, expect filename(s) now
- mov ax,$STDIN ; no file names, so use standard input
- jmp doread ; go begin the read of the file
-
- havfil: ; Begin scan for filename(s)
- call clrcnt ; go zero some counts
- mov di,offset filnam; where to store the filename
- xor cx,cx ; clear the filename length count
-
- filch: ; loop to collect the next filename
- lodsb ; get byte from [si] to al, increment si
- cmp al,' ' ; blank?
- je filend ; jump if so, have a filename
- cmp al,.HT ; tab?
- je filend ; jump if so, have a filename
- cmp al,.COMMA ; comma?
- je filend ; jump if so, have a filename
- cmp al,.CR ; end-of-line?
- je filend ; jump if so, have a filename
- stosb ; must be filename character, save it
- inc cx ; and count it
- jmp filch ; loop back for more
-
- filend: ; here when filename collected
- dec si ; backup to terminator character after name
- mov byte ptr [di],.NUL ; replace terminator by NUL
- push si ; save registers so we can scan for the
- mov fillen,cx ; save name length
- mov dx,offset fildta
- mov ah,$DOS_SETDTA
- int $DOS ; set new disk transfer area
-
- mov cx,0 ; attribute flags - find only normal files
- mov dx,offset filnam ; address of wild-carded filename
- mov ah,$DOS_FINDFIRST
- int $DOS ; find first matching file
- jmp short file00 ; go check error return
-
- filenext: ; here to find next matching file
- mov ah,$DOS_FINDNEXT
- int $DOS ; find next matching file
-
- file00: ; here to check error return of FINDFIRST
- ; or FINDNEXT
- jnb filmak ; jump if carry not set
-
- ; find file failed -- test error code returned in ax
-
- file01: cmp ax,18 ; no more files?
- jne file02 ; jump if not "no more files" condition
- jmp nxtfil ; no more files from this expansion
-
- file02:
- cmp ax,2 ; file not found?
- jne file03 ; jump if other error
- mov al,RC_NFND ; "file not found" error
- call setrc
- jmp nxtfil
-
- file03: ; some other undocumented error
- mov al,RC_FILE
- call setrc
- jmp nxtfil
-
- filmak: ; here after matching file found
- call makefile ; go attach path to name
- mov dx,offset fpath ; address of the full filename
- mov ah,$DOS_OPEN2
- mov al,$DOS_OPEN2_READ
- int $DOS ; open the file for input
- jnb filopn ; jump if carry not set, open okay
- jmp badfil ; carry set, open failed
-
- filopn: ; here after file opened (ax=handle)
- push ax ; save file handle
- mov dx,offset seplin; address of separator line
- mov cl,seplen ; and its length
- xor ch,ch ; clear top half of cx
- call writestr ; write separator line
- mov dx,offset fpath ; address of filename
- mov cx,fpalen ; and its length
- call writestr ; append filename to separator line
- cmp cntflg,FLAGSET ; was /C specified?
- je nocrlf ; jump if yes - will only write count
- mov dx,offset crlf ; else output CR LF
- mov cx,2
- call writestr
-
- nocrlf:
- pop ax ; restore file handle
-
- doread: ; here to read the open file
- mov bx,ax ; file handle
-
- nxtread: ; here for next block of file
- mov dx,offset buffer; where to put block
- mov cx,MAXBUF ; how long it is
- mov ah,$DOS_READ2
- int $DOS ; read the block
- jnb didread ; jump if carry not set, read okay
- jmp badread ; carry set on error
-
- didread:
- or ax,ax ; test count of bytes read
- jnz grepbuf ; if non-zero, go do pattern match
- cmp cntflg,FLAGSET ; end-of-file, was /C specified?
- jne nocnt ; no, all done on this file
- call writecnt ; yes, write the count of matches
-
- nocnt:
- cmp bx,$STDIN ; input from standard input file?
- jne doclose ; jump if not and close the file
- jmp nrmexit ; yes, no need to close, and all done
-
- doclose: ; here to close the file (handle in bx)
- mov ah,$DOS_CLOSE2
- int $DOS ; close the file
- jmp filenext ; and go for next one in wild list
-
- grepbuf: ; here to search block for pattern
- push bx ; save file handle
- mov bp,offset buffer; where the block is
- mov di,ax ; count of bytes in block
- cmp ax,MAXBUF ; block full?
- jge nopatch ; jump if yes
- mov bx,bp ; partial block, get address of block
- cmp byte ptr [bx+di-01],.LF ; is last character LF?
- je nopatch ; yes
- mov byte ptr [bx+di],.CR ; no, append CR LF at end of file
- inc di ; when it is missing, since
- mov byte ptr [bx+di],.LF ; the search algorithm expects this
- inc di ; terminator
-
- nopatch:
- push di ; save count of bytes in block
- push bp ; save block address
- mov dx,patlen ; pattern length
- dec dx ; pattern length - 1
-
- nxtscn:
- inc lineno ; increment line number
- pop bp ; block address
- mov di,bp
- pop cx ; count of bytes in block
- mov bx,cx
- mov al,.LF
- jcxz nofulln ; jump if no more bytes in block
- repnz scasb ; search for LF marking end-of-line
- jne nofulln ; jump if no end-of-line in block
- push cx ; save count of bytes remaining
- push di ; and location of end-of-line
- mov cx,di ; where LF is in block
- sub cx,bp ; compute length of line
- mov bx,cx ; save length of line
- dec cx ; then reduce for CR
- dec cx ; and LF
- jcxz notfnd ; jump if line is empty
- mov di,bp ; address of line in block
-
- samln: ; Loop to scan single line for pattern
- mov si,offset pattrn
- lodsb ; get byte from [si] to al, increment si
- cmp exactflg,FLAGSET; /E specified?
- je sam01 ; jump if yes
- call xnzscasb ; search for pattern byte, ignoring case
- jmp short sam02
- sam01:
- repnz scasb ; search for exact match with pattern byte
- sam02:
- jnz notfnd ; jump if byte not found
- cmp cx,dx ; found byte, is line longer than pattern?
- jb notfnd ; jump if not, not acceptable match
- push di ; save block address
- push cx ; and length of line
- mov cx,dx ; remaining length of pattern
- jcxz didfnd ; jump if pattern exhausted
- cmp exactflg,FLAGSET; /E specified?
- je sam03 ; jump if yes
- call xzcmpsb ; compare rest of pattern with current source
- jmp short sam04
- sam03:
- repz cmpsb ; compare for exact match
- sam04:
- je didfnd ; jump if found string match
- pop cx ; no match, restore old count
- pop di ; and source index
- jmp samln ; and go continue source scan
-
- didfnd: ; here when pattern found
- pop ax ; discard block address
- pop ax ; and line length on stack
- cmp notflg,FLAGSET ; was /V specified?
- jne negnot ; jump if not
- jmp nxtscn ; pattern found and /V says list non-matching
- ; lines, so go search on next line
-
- notfnd: ; here when pattern not found on current line
- cmp notflg,FLAGSET ; was /V specified?
- jne nxtscn ; jump if not
-
- negnot: ; here when (/V AND pattern NOT found) OR
- ; (NOT /V AND pattern found), i.e. matched
- cmp cntflg,FLAGSET ; was /C specified?
- jne nocount ; jump if not
- inc matches ; had /C, so increment pattern match count
- jmp nxtscn ; and go search next line
-
- nocount: ; here on match when line is to be printed
- push dx ; save dx (remaining length of pattern)
- cmp numflg,FLAGSET ; was /N specified?
- jne nolnnum ; jump if not
- call writelnnum ; had /N, write line number
-
- nolnnum: ; here after possibly writing line number
- mov dx,bp ; address of line in block
- mov cx,bx ; length of line
- call writestr ; go write matching line
- pop dx ; restore dx
- jmp nxtscn ; go search next line
-
- nofulln: ; here when line split across blocks;
- ; the input file pointer must be backed
- ; up to the beginning of the current line
- mov dx,bx ; length of line
- pop bx ; file handle
- or dx,dx ; test line length
- jz nxtblock ; jump if 0
- neg dx ; -(length of line)
- mov cx,-1 ; (cx,dx) = file offset
- mov al,$DOS_LSEEK_CURRENT
- mov ah,$DOS_LSEEK
- int $DOS ; reposition to beginning of current line
- jc badread ; abort if lseek failed
-
- nxtblock:
- jmp nxtread ; go for next block
-
- badread: ; here on lseek/read failure
- mov al,RC_READ ; return code
- call setrc
-
- bad01:
- cmp bx,$STDIN ; reading standard input?
- jne bad02 ; jump if not
- jmp nrmexit ; yes, all done
-
- bad02:
- mov ah,$DOS_CLOSE2 ; no, close the file
- int $DOS
- mov dx,offset rdderr; error message
- mov cl,rddlen ; and length
- jmp dowrite ; write message
-
- badfil: ; here on open failure
- mov dx,offset fnderr; error message
- mov cl,fndlen ; and length
- mov al,RC_FILE ; return code
- call setrc
-
- dowrite: ; here to print error message and file name
- call writeerr
- call writefil
-
- nxtfil: ; here to find next file on command line
- pop si ; address of last byte examined
- call skipsp ; flush white space
- or bx,bx ; end-of-line reached?
- jnz nrmexit ; yes, all done
- jmp havfil ; no, go collect file name
-
- setrc: ; routine to set return code from al
- cmp al,rc ; higher than current one?
- jbe setrc1 ; jump if not
- mov rc,al ; else save new one
- setrc1:
- ret ; return to caller
-
-
- ; routine to build a full filename in fpath (terminated by NUL)
- ; from wild-carded path in filnam and filename in fname, since
- ; FINDFIRST/FINDNEXT do not return a complete file spec
-
- makefile:
- push ax ; save registers
- push cx
- push si
- push di
-
- mov di,offset fpath ; where full file spec is to go
- mov si,offset filnam; where wild card spec is
- cld ; clear direction flag for positive increment
- push di ; save separator address+1
-
- ; Copy filnam (up to last non-NUL) into fpath, remembering location
- ; of last separator (:/\) so we can append fname to it. DOS should
- ; have done this!!! Note that this omission prevents wildcarding
- ; directory names, since there is no way to determine the directory
- ; name when only the file name is returned by FINDFIRST/FINDNEXT
-
- make01: ; loop copying filnam into fpath
- lodsb ; source byte to al, increment si
- cmp al,.NUL ; end-of-string?
- je make03 ; yes, all done
- stosb ; no, store byte in al to [di], increment di
- cmp al,':' ; device separator?
- je make02 ; jump if separator
- cmp al,'\' ; path separator?
- je make02 ; jump if so
- cmp al,'/' ; alternate path separator?
- je make02 ; jump if so
- jmp short make01 ; loop for next character
-
- make02:
- pop ax ; discard old address
- push di ; remember separator address (+1)
- jmp short make01 ; loop for more
-
- make03: ; here at end-of-string. fpath now has
- ; copy of filnam (wild-carded spec)
- pop di ; address of last separator+1
- mov si,offset fname
-
- make04: ; loop copying fname into fpath after term.
- lodsb ; byte from [si] to al, increment si
- stosb ; byte from al to [di], increment di
- cmp al,.NUL ; end-of-string yet?
- jne make04 ; loop if more
-
- xor cx,cx ; clear count
- mov si,offset fpath ; address of fpath
-
- make05:
- lodsb ; loop counting characters
- cmp al,.NUL ; end-of-string yet?
- je make06 ; yes
- inc cx ; no, count the character
- jmp short make05 ; loop for more
-
- make06:
- mov fpalen,cx ; save fpath length
- pop di ; restore registers saved at entry
- pop si
- pop cx
- pop ax
- ret ; return to caller
-
- errexit: ; here for error exit
- cmp rc,RC_PARM ; bad parameter?
- je erruse ; yes, print usage message
- cmp rc,RC_PATT ; bad
- je erruse ; yes, print usage message
- jmp nrmexit ; else just exit
-
- erruse: ; here to print usage message
- mov dx,offset useerr; message address
- mov cl,uselen ; and length
- call writedserr
-
- nrmexit: ; here to exit to DOS when done
- mov al,rc ; set return code
- mov ah,$DOS_EXIT
- int $DOS ; exit to DOS
-
- skipsp: ; routine to skip white space on command line
- cld ; clear direction flag to increment si
- xor bx,bx ; clear end-of-line flag returned in bx
-
- havesp: ; loop skipping white space
- lodsb ; get byte from [si] to al, increment si
- cmp al,' ' ; blank?
- je havesp ; yes, keep looping
- cmp al,.HT ; tab?
- je havesp ; yes, keep looping
- cmp al,.COMMA ; comma
- je havesp ; yes, keep looping
- cmp al,.CR ; end-of-line?
- jne nocr ; jump if not - hit non-white space character
- mov bx,ax ; end-of-line hit, set return flag non-zero
- nocr:
- dec si ; backup to last white space character
- ret ; return to caller with bx set to flag
-
- clrcnt: ; routine to clear search counts
- mov byte ptr matches,0 ; clear match count
- mov byte ptr lineno,0 ; and line number
- ret
-
- writecnt: ; routine to write count
- push bx ; save file handle
- cmp bx,$STDIN ; standard input?
- je nocolon ; jump if yes (no file name output)
- mov dx,offset colon ; no, follow file name by colon
- mov cx,2 ; string length
- call writestr ; write the colon
-
- nocolon:
- mov ax,matches ; count of matches
- mov di,offset intstr; message
- call writeint ; write the integer
- mov dx,offset intstr; message
- call writestr ; write the message
- mov dx,offset crlf ; and follow it by
- mov cx,2 ; a CR LF
- call writestr
- pop bx ; restore the file handle
- ret ; return to caller
-
- writelnnum: ; here to write a line number
- push bx ; save file handle
- push dx ; and remaining pattern length
- mov ax,lineno ; line count
- mov di,offset intstr; message
- call writeint ; write the integer
- mov byte ptr [di],']' ; follow it by left square bracket
- inc cx
- inc cx ; increment count by 2
- mov dx,offset linstr; address of string
- call writestr ; write [nnnn] string
- pop dx ; restore pattern length
- pop bx ; and file handle
- ret
-
- writestr: ; routine to write string at ds:dx,length in cx
- mov bx,$STDOUT
- mov ah,$DOS_WRITE2
- int $DOS
- ret
-
- writeint: ; routine to format integer in ax to [di]
- mov bx,10
- xor cx,cx ; clear count of bytes written
-
- intdiv:
- inc cx ; increment count of bytes written
- cmp ax,bx ; remainder < 10?
- jb intdone ; jump if yes, have only single digit left
- xor dx,dx ; clear dx (top half of 32-bit numerator)
- div bx ; (ax,dx)/10 to ax, (ax,dx) mod 10 to dx
- add dl,'0' ; make into ASCII digit
- push dx ; save on stack
- jmp intdiv ; keep collecting digits
-
- intdone:
- add al,'0' ; make into ASCII digit
- push ax ; save on stack
- mov bx,cx ; save count of digits
-
- intsto: ; loop to pull digits from stack
- pop ax ; get a digit
- stosb ; store in target string
- loop intsto ; loop while cx > 0
- mov cx,bx ; count of digits
- ret ; return to caller
-
- writefil: ; routine to write file name and CR LF
- mov dx,offset fpath ; full filename
- mov cx,fpalen ; and length
- call writeerr ; write it
- mov dx,offset crlf
- mov cx,2
- call writeerr ; write CR LF
- ret ; return to caller
-
- writedserr: ; routine to write error message from ds:
- call writeerr
- ret
-
- writeerr: ; routine to write error message
- xor ch,ch
- mov bx,$STDERR
- mov ah,$DOS_WRITE2
- int $DOS
- ret
-
- lcuc: ; routine to convert al to upper-case
- cmp al,'a' ; less than 'a'
- jb ok ; yes, cannot be lower-case
- cmp al,'z' ; greater than 'z'
- jg ok ; yes, cannot be lower-case
- and al,not 20h ; turn off lc bit
-
- ok:
- ret ; return to caller
-
- ;
- ; Begin translated equivalent of REPNZ SCASB
- ;
- xnzscasb:
- push ax ; save ax and
- push bx ; bx during this loop
- mov bx, offset xtable
- xlat byte ptr xtable ; al <- xtable(al) - translated pattern byte
- mov ah,al ; translated pattern byte
-
- loop1:
- mov al,es:byte ptr [di] ; source byte
- xlat byte ptr xtable ; translate source byte in al
- inc di ; point to next byte (like scasb does)
- cmp ah,al ; source = pattern?
- loopne loop1 ; decrement cx and loop while no match
-
- pop bx ; restore bx
- pop ax ; and ax
- ret
- ;
- ; End translated equivalent of REPNZ SCASB
- ;
-
- ;
- ; Begin translated equivalent of REPZ CMPSB
- ;
- xzcmpsb:
- push ax ; save ax and
- push bx ; bx during this loop
- mov bx, offset xtable
-
- loop2:
- mov al,byte ptr [si];pattern byte
- xlat byte ptr xtable ; al <- xtable(al) - translated pattern byte
- mov ah,al ; translated pattern byte
- mov al,es:byte ptr [di] ; source byte
- xlat byte ptr xtable ; translate source byte in al
- inc si ; point to next byte (like cmpsb does)
- inc di ; point to next byte (like cmpsb does)
- cmp ah,al ; source = pattern?
- loope loop2 ; decrement cx and loop while match
-
- pop bx ; restore bx
- pop ax ; and ax
- ret
- ;
- ; End translated equivalent of REPZ CMPSB
- ;
- xtable equ $ ; translation table mapping lower case into upper
- xbyte=0
- rept 97 ; NUL .. "`" --> themselves
- db xbyte
- xbyte=xbyte+1
- endm
- xbyte=65
- rept 26 ; "a".."z" --> "A".."Z"
- db xbyte
- xbyte=xbyte+1
- endm
- xbyte=123
- rept 133 ; "["..0FFH --> themselves
- db xbyte
- xbyte=xbyte+1
- endm
-
- patlen dw ; 0332
- pattrn db 128 dup (0) ; 0334
- fillen dw ; 03b4
- filnam db 65 dup (0) ; 03b6
- db 9 dup (0)
-
- ; file disk transfer area for wild-card expansion
- even
- fildta db 21 dup (?) ; reserved for DOS
- db 0 ; attribute found - 0 means only normal files
- dw ? ; file's time
- dw ? ; file's date
- dw ? ; low word of file size
- dw ? ; high word of file size
- fname db 13 dup (?) ; file name (asciz string)
-
- ; end of file disk transfer area
-
- fpalen dw 0 ; length of fpath (up to before NUL)
- fpath db 65 dup (0) ; space for expanded file name from dta
-
-
- baddos db "Incorrect DOS version$" ; 00
- crlf db .CR,.LF ; 16
- numerr db "XFIND: Invalid number of parameters",.CR,.LF ; 18
- numlen db numlen-numerr ; 3C
- synerr db "XFIND: Syntax error",.CR,.LF ; 3D
- synlen db synlen-synerr ; 51
- fnderr db "XFIND: File not found " ; 52
- fndlen db fndlen-fnderr ; 67
- rdderr db "XFIND: Read error in " ; 68
- rddlen db rddlen-rdderr ; 7C
- prmerr db "XFIND: Invalid Parameter " ; 7D
- prmlen db prmlen-prmerr ; 95
- useerr db "Usage: XFIND [/C] [/E] [/N] [/V] "
- db '"string"" [[d:][path]filename[.ext] [,]]',.CR,.LF
- db "/C : match count only",.CR,.LF
- db "/E : exact match with respect to letter case required",.CR,.LF
- db "/N : print line numbers of matching lines",.CR,.LF
- db "/V : invert match - display lines NOT containing pattern"
- db .CR,.LF
- uselen db uselen-useerr
- seplin db .CR,.LF,"---------- " ; 96
- seplen db SEPLEN-SEPLIN ; A3
- if ($-findc) mod 256
- org ($-findc)+256-(($-findc) mod 256) ; Start buffer on 256n
- ; boundary
- endif
- buffer EQU THIS BYTE ; There must be space for MAXBUF dup (?)
- ; here, plus some more on top for the
- ; stack. This trick is used instead of
- ; MAXBUF dup (?) because even with
- ; initialization to (?), LINK creates a
- ; .EXE file proportionate in size to
- ; this value...baahhh!!!
- findc ends
- end start